import json
import os.path
import sys
from os import path

import pymysql
from PySide6 import QtCore, QtWidgets
from PySide6.QtGui import QKeySequence, QShortcut, QAction
from PySide6.QtWidgets import QMainWindow, QMessageBox, QTreeWidgetItem, QTreeWidget, QMenu, QInputDialog, QLineEdit, \
    QHeaderView, QPushButton, QListWidget, QListWidgetItem, QFileDialog
from PySide6.QtUiTools import QUiLoader
from PySide6.QtCore import Qt, QPoint

from controllers.dialog_add_table import DialogAddTable
from global_variables import GlobalVariables
from mysql.mysqldump import MysqlDumpSql
from util import common
from util.common import hum_convert


class TableList(QMainWindow):

    def __init__(self, app):
        super().__init__()
        self.app = app
        self.ui = app.ui

        self.init()
        self.__data_list_fill_data__ = self.app.data_list_fill_data
        self.__data_list_filter__ = self.app.data_list_filter
        self.__field_list_fill_data__ = self.app.field_list_fill_data
        self.mysqldb = GlobalVariables.DATABASE_OBJ
        self.prev_table_name = None

    def init(self):
        self.ui.table_list: QListWidget
        self.ui.table_list.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection)

        self.ui.table_list.currentItemChanged.connect(self.selected_table_event)
        self.ui.table_list.itemDoubleClicked.connect(self.table_list_item_double_clicked)
        self.ui.table_list.itemChanged.connect(self.table_list_item_changed)
        self.ui.add_table_button.clicked.connect(self.add_table_event)
        self.ui.del_table_button.clicked.connect(self.delete_item)
        self.ui.refresh_table_button.clicked.connect(self.refresh_items)
        self.ui.table_search.textChanged.connect(self.table_search_text_changed)

        # 右键菜单
        self.ui.table_list.setContextMenuPolicy(Qt.CustomContextMenu)
        self.ui.table_list.customContextMenuRequested.connect(self.show_menu)
        # 删除表按钮由于没有选中，设置为禁用
        self.ui.del_table_button.setEnabled(False)

    def show_menu(self, point: QPoint):
        menu = QMenu(self.app)

        item = self.ui.table_list.itemAt(point)
        if item is not None:
            common.add_action(menu, '删除数据表', self.delete_item)
            common.add_action(menu, '清空数据表', self.truncate_table)
            common.add_action(menu, '导出数据表', self.export_table)

        common.add_action(menu, '导入数据表', self.import_table)
        desk_point = self.ui.table_list.mapToGlobal(point)
        menu.exec_(desk_point)

    # 删除数据表
    def delete_item(self):
        table_list: QListWidget = self.ui.table_list

        item: QListWidgetItem = table_list.currentItem()
        if not isinstance(item, QListWidgetItem):
            return
        table_name = item.text()
        result = QMessageBox.question(self, '确认删除', f'是否确认删除数据表 {table_name}')
        if result != QMessageBox.StandardButton.Yes:
            return
        self.mysqldb.table_delete(table_name)
        self.app.database_select.selected_database_event(self.ui.database_select.currentIndex())

        tab_widget = self.ui.tab_table_widget.currentWidget()
        if tab_widget.objectName() in [
            'tab_table_content',
            'tab_table_struct',
            'tab_table_information',
        ]:
            self.__data_list_fill_data__.data_list_clear()
            self.__field_list_fill_data__.field_list_clear()
            self.app.tab_table_information.tab_table_information_clear()
        else:
            pass

    # 清空数据表
    def truncate_table(self):
        table_list: QListWidget = self.ui.table_list
        if len(table_list.selectedItems()) == 0:
            return
        item: QListWidgetItem = table_list.selectedItems()[0]
        table_name = item.text()
        result = QMessageBox.question(self, '确认清空', f'是否确认清空数据表 {table_name}')
        if result != QMessageBox.StandardButton.Yes:
            return
        self.mysqldb.table_truncate(item.text())
        tab_widget = self.ui.tab_table_widget.currentWidget()
        if tab_widget.objectName() == 'tab_table_content':
            self.__data_list_fill_data__.refresh_items()

    # 切换数据表事件
    def selected_table_event(self, item: QListWidgetItem):
        if item is None:
            return
        table_name = item.text()
        self.prev_table_name = table_name
        self.ui.del_table_button.setEnabled(True)

        # 数据表信息
        self.table_information_fill_data(table_name)
        tab_widget = self.ui.tab_table_widget.currentWidget()
        if tab_widget.objectName() == 'tab_table_content':
            limit = int(self.ui.data_page_limit.currentText())
            page_num = GlobalVariables.DATA_LIST_PAGE_NUM
            self.__data_list_filter__.reset_filter()
            self.__data_list_fill_data__.data_list_fill_data(table_name=table_name, limit=limit, page_num=page_num)
        elif tab_widget.objectName() == 'tab_table_struct':
            self.__field_list_fill_data__.fill_data(table_name)
        elif tab_widget.objectName() == 'tab_table_information':
            self.app.tab_table_information.tab_table_information_fill_data(table_name)
        elif tab_widget.objectName() == 'tab_sql_query':
            pass

    def table_list_item_double_clicked(self, item: QListWidgetItem):
        item.setFlags(item.flags() | QtCore.Qt.ItemFlag.ItemIsEditable)
        if not item.isSelected():
            item.setSelected(True)

    def table_list_item_changed(self, item: QListWidgetItem):
        if item.text() == getattr(item, 'table_name'):
            return

        current_table_name = item.text()
        old_table_name = getattr(item, 'table_name')
        if len(current_table_name) == 0:
            item.setText(old_table_name)
            return
        try:
            self.mysqldb.table_rename(old_table_name, current_table_name)
        except pymysql.err.OperationalError as e:
            code, msg = e.args
            QMessageBox.critical(self, '重命名错误', str(code) + "\t" + msg)
            raise e
        setattr(item, 'table_name', current_table_name)
        self.app.tab_sql_query.sync_table_and_column()

    def add_table_event(self):
        dialog = DialogAddTable(self.ui.table_list, self.app)
        # dialog显示后，主控件不可点击
        dialog.setWindowModality(Qt.ApplicationModal)
        dialog.show()

    def refresh_items(self):
        self.ui.table_list: QListWidget
        self.app.database_select.selected_database_event(self.ui.database_select.currentIndex())
        if self.prev_table_name is None:
            self.ui.table_list.setCurrentRow(0)
            return

        for row in range(0, self.ui.table_list.count()):
            if self.ui.table_list.item(row).text() == self.prev_table_name:
                self.ui.table_list.setCurrentRow(row)
                return

    # 填充数据表列表
    def table_list_fill_data(self):
        self.ui.table_list: QListWidget
        self.ui.table_list.itemChanged.disconnect(self.table_list_item_changed)
        self.ui.table_list.currentItemChanged.disconnect(self.selected_table_event)
        self.ui.table_list.clear()
        GlobalVariables.LIST_DATABASE_TABLES = []
        for table in self.app.mysqldb.show_tables():
            GlobalVariables.LIST_DATABASE_TABLES.append(table)
            self.ui.table_list.addItem(self.list_widget_item(table))
        self.ui.table_list.itemChanged.connect(self.table_list_item_changed)
        self.ui.table_list.currentItemChanged.connect(self.selected_table_event)

    def list_widget_item(self, text):
        item = QListWidgetItem(self.ui.table_list)
        setattr(item, 'table_name', text)
        item.setText(text)
        return item

    # 数据表搜索框事件
    def table_search_text_changed(self, text: str):
        self.ui.table_list.itemChanged.disconnect(self.table_list_item_changed)
        self.ui.table_list.clear()

        if len(text) == 0:
            for table in GlobalVariables.LIST_DATABASE_TABLES:
                self.ui.table_list.addItem(self.list_widget_item(table))
            self.ui.table_list.itemChanged.connect(self.table_list_item_changed)
            return

        list_sub_str = text.split('|')
        print(list_sub_str)
        for table in GlobalVariables.LIST_DATABASE_TABLES:
            for sub_str in list_sub_str:
                if len(sub_str) == 0:
                    continue
                if table.count(sub_str) > 0:
                    self.ui.table_list.addItem(self.list_widget_item(table))
                    continue
        self.ui.table_list.itemChanged.connect(self.table_list_item_changed)

    def get_table_name(self):
        item = self.ui.table_list.currentItem()
        if isinstance(item, QListWidgetItem):
            return item.text()
        return None

    def table_information_fill_data(self, table_name: str):
        select_database = self.ui.database_select.currentText()
        data = self.mysqldb.table_information(select_database, table_name)
        if data is None:
            return
        # 左下角 table information 数据填充
        if data.get('CREATE_TIME') is not None:
            self.ui.label_table_created.setText('created: ' + data['CREATE_TIME'].strftime("%Y-%m-%d %H:%M:%S"))
        self.ui.label_table_engine.setText('engine: ' + (data['ENGINE'] if isinstance(data['ENGINE'], str) else "-"))
        self.ui.label_table_rows.setText('rows: ' + str(data['TABLE_ROWS']))
        self.ui.label_table_size.setText('size: ' + str(hum_convert(data['DATA_LENGTH'])))
        if isinstance(data['TABLE_COLLATION'], str):
            encoding = GlobalVariables.MAP_COLLECTION_CHARSET.get(data['TABLE_COLLATION'])
        else:
            encoding = '-'
        self.ui.label_table_encoding.setText('encoding: ' + encoding)
        self.ui.label_table_auto_increment.setText(
            'auto_increment: ' + ('-' if data['AUTO_INCREMENT'] is None else str(data['AUTO_INCREMENT']))
        )

    # 导出数据表
    def export_table(self):
        table_list: QListWidget = self.ui.table_list
        if len(table_list.selectedItems()) == 0:
            return
        save_dir = "/"
        if sys.platform == "darwin":
            save_dir = f"/Users/{os.environ['USER']}/Downloads/"
            if not path.exists(save_dir):
                save_dir = "/"
        filepath, f_type = QFileDialog.getSaveFileName(self, "文件保存", save_dir, 'sql(*.sql)')
        if len(filepath) == 0:
            return
        dumper = MysqlDumpSql()
        dumper.set_export_table_list([item.text() for item in table_list.selectedItems()])
        dumper.start(filepath)
        QMessageBox.information(self, "提示", "导出完成")

    # 导入数据
    def import_table(self):
        filepath, f_type = QFileDialog.getOpenFileName(self, "选择导入文件", "/", 'sql(*.sql)')
        if len(filepath) == 0:
            return
        dumper = MysqlDumpSql()
        try:
            dumper.restore(filepath)
        except Exception as e:
            code, msg = e.args
            QMessageBox.critical(self, '错误', msg)
        else:
            QMessageBox.information(self, "提示", "导入完成")
